package edu.arizona.sista.learn.model.groups;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.arizona.sista.learn.util.Utils;

/**
 * Models of various grouping definitions.
 * 
 * @author Anh Tran
 *
 */
public class GroupDefinitions {
	
	private static final String OPS_SUFFIX = "-ops.txt";
	
	
	/**
	 * Infer groups by applying _one_ of the following gaze-based grouping rules:
	 * 	1. Group-Attention: participants must spend enought time focusing on other
	 * 		members in the group.
	 * 	2. Shared-Attention: all participants must spend enough time looking at
	 * 		the same object.
	 * @param scene A video scene.
	 * @param minAttentionRatio Minimum attention threshold.
	 * @return Groups that were removed for not meeting the defined requirements.
	 */
	public static List<Group> gazeBased(Scene scene, float minAttentionRatio) {
		return gazeBased(scene, minAttentionRatio, true);
	}
	
	public static List<Group> gazeBased(Scene scene, float minAttentionRatio, boolean out) {
		
		List<Group> filtered = new ArrayList<Group>();
		StringBuilder opsOut = new StringBuilder();

		// Sort groups based on intervals
		Collections.sort(scene.getGroups());
		
		// Clone the list of groups to operate on (NOTE: this is a shallow copy!!)
		List<Group> groups = new ArrayList<Group>(scene.getGroups());
		
		// Within-group attention
		// Find groups where members are required to look at each other
		List<Group> remaining = GroupingRules.minGroupAttentionGazeRatio(groups,
				minAttentionRatio, opsOut);
		
		// Shared group attention
		// For groups that didn't focus on each other, perhaps they are
		// all focusing on a shared object.
		Collections.sort(remaining);
		filtered = GroupingRules.minSharedAttentionGazeRatio(remaining, minAttentionRatio, opsOut);
		
		// Now remove the filtered groups (groups that did not pass both rules)
		// from the actual list of groups of the scene.
		scene.getGroups().removeAll(filtered);
		
		// Dump operations taken
		if (out) {
			System.out.println(opsOut.toString());
			Utils.toFile(opsOut, Utils.OUTDIR + scene.getName() + OPS_SUFFIX, true);
		}
		
		return filtered;
	}
	
	/**
	 * Infer groups by applying the following spatio-temporal grouping rules:
	 * 	1. MinDuration: remove all groups that exist for less than durationWindow
	 *  2. Continuity-of-Participants: merge end-to-end groups that share atleast
	 *  	50% of their repsective participants.
	 *  3. MinParticipants: remove all groups with less than minParticipants members.
	 * @param scene A video scene.
	 * @param durationWindow Minimum duration window.
	 * @param minParticipants Minimum number of participants.
	 * @return Groups that were removed for not meeting the defined requirements.
	 */
	public static List<Group> spatioTemporal(Scene scene, int durationWindow,
			int minParticipants) {
		return spatioTemporal(scene, durationWindow, minParticipants, true);
	}
	
	public static List<Group> spatioTemporal(Scene scene, int durationWindow,
			int minParticipants, boolean out) {
		
		List<Group> filtered = new ArrayList<Group>();
		StringBuilder opsOut = new StringBuilder();

		// Sort groups based on intervals
		Collections.sort(scene.getGroups());
		
		// Duration requirement
		filtered.addAll(GroupingRules.minDuration(scene.getGroups(), durationWindow, opsOut));
		
		// Continuity of participants requirement
		float minSharedRatio = .5f;
		GroupingRules.mergeOverlappingParticipants(scene.getGroups(), durationWindow,
				minSharedRatio, opsOut);
		
		// Min # of people requirement
		filtered.addAll(GroupingRules.minParticipants(scene.getGroups(), minParticipants, opsOut));
		
		// Dump operations taken
		if (out) {
			System.out.println(opsOut.toString());
			Utils.toFile(opsOut, Utils.OUTDIR + scene.getName() + OPS_SUFFIX, true);
		}
		
		return filtered;
	}

}
